package com.easylinkin.linkappapi.penetsecuremanage.service.impl;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.easylinkin.linkappapi.common.service.CommonService;
import com.easylinkin.linkappapi.penetsecuremanage.dto.RailLinkappWorkflowResolveDTO;
import com.easylinkin.linkappapi.penetsecuremanage.entity.RailLinkappWorkflowResolve;
import com.easylinkin.linkappapi.penetsecuremanage.mapper.RailLinkappWorkflowResolveMapper;
import com.easylinkin.linkappapi.penetsecuremanage.service.IRailLinkappWorkflowResolveService;
import com.easylinkin.linkappapi.penetsecuremanage.vo.RailLinkappWorkflowResolveVO;
import com.easylinkin.linkappapi.security.context.LinkappUserContextProducer;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.io.*;
import java.net.*;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.zip.CRC32;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;


@Service
@Slf4j
public class RailLinkappWorkflowResolveServiceImpl extends ServiceImpl<RailLinkappWorkflowResolveMapper, RailLinkappWorkflowResolve> implements IRailLinkappWorkflowResolveService {
    @Autowired
    private LinkappUserContextProducer linkappUserContextProducer;
    @Resource
    private CommonService commonService;
    @Override
    public List<RailLinkappWorkflowResolveVO> getList(RailLinkappWorkflowResolveDTO dto) {
        dto.setTenantId(linkappUserContextProducer.getNotNullCurrent().getTenantId());
        return baseMapper.getList(dto);
    }

    @Override
    public Integer countByOrgName(String tenantId, String name, String id) {
        return baseMapper.countByOrgName(tenantId,name,id);
    }

    @Override
    public void add(RailLinkappWorkflowResolveDTO dto) {
        String tenantId = linkappUserContextProducer.getNotNullCurrent().getTenantId();
        //查询最大sortIndex
        Integer iMax = baseMapper.countIndexMaxByTenantId(tenantId);
        if (Objects.isNull(iMax)){
            iMax = 0;
        }
        String id = UUID.randomUUID().toString().replaceAll("-", "");
        RailLinkappWorkflowResolve  WorkflowResolve = new RailLinkappWorkflowResolve();
        WorkflowResolve.setId(id);
        WorkflowResolve.setName(dto.getName());
        WorkflowResolve.setTenantId(tenantId);
        WorkflowResolve.setSortIndex((iMax+1));
        WorkflowResolve.setWorkflowFileUrl(dto.getWorkflowFileUrl());
        commonService.setCreateAndModifyInfo(WorkflowResolve);
        baseMapper.insert(WorkflowResolve);
    }

    @Override
    public void edit(RailLinkappWorkflowResolveDTO dto) {
        RailLinkappWorkflowResolve byId = getById(dto.getId());
        byId.setName(dto.getName());
        baseMapper.updateById(byId);
    }

    @Override
    public void downloadOneByZip(List<String> fileUrls, HttpServletResponse response,String zipfileName) throws IOException {
        // 设置响应头
        response.setContentType("application/zip");
       // response.setHeader("Content-Disposition", "attachment; filename=\"download.zip\"");
        response.addHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(zipfileName, "UTF8"));
       /* response.setHeader("Content-Disposition",
                "attachment; filename=\"" + zipfileName + "\";" +
                        "filename*=UTF-8''" + URLEncoder.encode(zipfileName, "UTF-8"));*/
        response.setCharacterEncoding("UTF-8");
        //String[] split = workflowFileUrl.split(",");
        // 使用缓冲输出流
        try (BufferedOutputStream bufferedOut = new BufferedOutputStream(response.getOutputStream());
             ZipOutputStream zos = new ZipOutputStream(bufferedOut)) {

            // 关键：使用 STORED 模式并手动设置 CRC 和大小
            zos.setMethod(ZipOutputStream.STORED);

            for (String fileUrl : fileUrls) {
                try {
                    if (StringUtils.isEmpty(fileUrl)){
                        continue;
                    }
                    String safeFileName = safeEncodeFileName(fileUrl);
                    URI uri = new URI(safeFileName);
                    URL url = uri.toURL();
                    // 打开连接
                    HttpURLConnection connection = (HttpURLConnection) url.openConnection();
                    connection.setRequestMethod("GET");
                    connection.setConnectTimeout(5000);
                    connection.setReadTimeout(30000);
                    connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/91.0.4472.124 Safari/537.36");
                    connection.setRequestProperty("Accept", "*/*");
                    // 处理重定向
                    connection.setInstanceFollowRedirects(true);
                    try (InputStream in = new BufferedInputStream(connection.getInputStream());
                         ByteArrayOutputStream baos = new ByteArrayOutputStream()) {
                        // 1. 先完整读取文件内容到内存
                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = in.read(buffer)) != -1) {
                            baos.write(buffer, 0, bytesRead);
                        }
                        byte[] fileData = baos.toByteArray();
                        // 2. 计算CRC校验和
                        CRC32 crc = new CRC32();
                        crc.update(fileData);
                        // 3. 创建ZIP条目并设置必要属性
                        String fileName = getSafeFileName(fileUrl, connection.getContentType());
                        fileName = URLDecoder.decode(fileName, String.valueOf(StandardCharsets.UTF_8));
                        ZipEntry entry = new ZipEntry(fileName);
                        entry.setMethod(ZipEntry.STORED); // 必须与setMethod一致
                        entry.setSize(fileData.length);    // 必须设置
                        entry.setCompressedSize(fileData.length); // 必须设置
                        entry.setCrc(crc.getValue());      // 必须设置
                        // 4. 写入条目和数据
                        zos.putNextEntry(entry);
                        zos.write(fileData);
                        zos.closeEntry();
                    }
                } catch (Exception e) {
                    // 记录错误但继续处理其他文件
                    System.err.println("文件处理失败: " + fileUrl + " - " + e.getMessage());
                }
            }

            // 关键：确保所有数据刷新到输出流
            zos.finish();
            bufferedOut.flush();

        } catch (Exception e) {
            response.reset();
            response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            response.getWriter().write("ZIP创建失败: " + e.getMessage());
        }
    }

    //http://172.16.10.25:19000/linkapp/linkapp/public/%E8%83%8C%E9%9D%A2.png
    // 安全的文件名生成
    private String getSafeFileName(String fileUrl, String contentType) {
        String fileName = fileUrl.substring(fileUrl.lastIndexOf('/') + 1);

        // 移除查询参数
        int queryIndex = fileName.indexOf('?');
        if (queryIndex > 0) {
            fileName = fileName.substring(0, queryIndex);
        }

        // 添加扩展名（如果需要）
        // 3. 添加扩展名（如果需要）
        if (!fileName.contains(".") && contentType != null) {
            String ext = getExtensionFromContentType(contentType);
            if (!ext.isEmpty()) fileName += "." + ext;
        }
        // 4. 安全处理
        fileName = sanitizeFileName(fileName);

        // 移除非法字符
        return UUID.randomUUID().toString().substring(0, 4) + "_" + fileName;
    }
    private String sanitizeFileName(String fileName) {
        // 移除非法字符
        fileName = fileName.replaceAll("[\\\\/:*?\"<>|]", "_");
        // 截断过长文件名
        if (fileName.length() > 100) {
            fileName = fileName.substring(0, 50) + "..." + fileName.substring(fileName.length() - 20);
        }
        return fileName;
    }
    // 安全编码文件名（符合RFC 3986标准）
    private String safeEncodeFileName(String fileName) throws UnsupportedEncodingException {
        try {
            // 使用Java的URI类进行分段编码
            return new URI(null, null, fileName, null).toASCIIString();
        } catch (URISyntaxException e) {
            log.warn("文件名编码失败，使用备用方案: {}", fileName);
            // 备用方案：只编码非ASCII字符
            return URLEncoder.encode(fileName, StandardCharsets.UTF_8.toString())
                    .replace("+", "%20") // 空格特殊处理
                    .replace("%28", "(") // 保留括号
                    .replace("%29", ")")
                    .replace("%27", "'")
                    .replace("%2D", "-")
                    .replace("%2E", ".")
                    .replace("%5F", "_");
        }
    }
    // 从Content-Type获取扩展名
    private String getExtensionFromContentType(String contentType) {
        if (contentType == null) return "";

        // 移除字符集信息
        contentType = contentType.split(";")[0].trim().toLowerCase();
        // 常见文件类型映射
        switch (contentType) {
            case "application/pdf": return "pdf";
            case "image/jpeg": return "jpg";
            case "image/png": return "png";
            case "image/gif": return "gif";
            case "image/bmp": return "bmp";
            case "image/svg+xml": return "svg";
            case "image/tiff": return "tiff";
            case "image/webp": return "webp";
            case "application/zip": return "zip";
            case "application/x-rar-compressed": return "rar";
            case "application/x-tar": return "tar";
            case "application/x-gzip": return "gz";
            case "text/plain": return "txt";
            case "text/csv": return "csv";
            case "application/vnd.ms-excel": return "xls";
            case "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet": return "xlsx";
            case "application/msword": return "doc";
            case "application/vnd.openxmlformats-officedocument.wordprocessingml.document": return "docx";
            case "application/vnd.ms-powerpoint": return "ppt";
            case "application/vnd.openxmlformats-officedocument.presentationml.presentation": return "pptx";
        }

        // 从完整MIME类型提取
        int slashIndex = contentType.lastIndexOf('/');
        if (slashIndex != -1 && slashIndex < contentType.length() - 1) {
            String ext = contentType.substring(slashIndex + 1);
            // 特殊处理复合类型
            if (ext.equals("vnd.openxmlformats-officedocument.wordprocessingml.document")) {
                return "docx";
            }
            return ext;
        }

        return "dat";
    }
}
